package com.lin.project.cloudnative.controller;

import cn.hutool.core.date.DateUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.lin.project.cloudnative.annotation.AuthCheck;
import com.lin.project.cloudnative.common.BaseResponse;
import com.lin.project.cloudnative.common.DeleteRequest;
import com.lin.project.cloudnative.common.ErrorCode;
import com.lin.project.cloudnative.common.ResultUtils;
import com.lin.project.cloudnative.exception.BusinessException;
import com.lin.project.cloudnative.model.codesandbox.ExecuteCodeRequest;
import com.lin.project.cloudnative.model.codesandbox.ExecuteCodeResponse;
import com.lin.project.cloudnative.model.dto.testTask.TestTaskAddRequest;
import com.lin.project.cloudnative.model.dto.testTask.TestTaskQueryRequest;
import com.lin.project.cloudnative.model.dto.testTask.TestTaskUpdateRequest;
import com.lin.project.cloudnative.model.dto.testTask.UploadFileRequest;
import com.lin.project.cloudnative.model.entity.TestCase;
import com.lin.project.cloudnative.model.entity.TestTask;
import com.lin.project.cloudnative.model.entity.User;
import com.lin.project.cloudnative.model.vo.UploadFileVO;
import com.lin.project.cloudnative.service.TestCaseService;
import com.lin.project.cloudnative.service.TestTaskService;
import com.lin.project.cloudnative.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.similarity.CosineSimilarity;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 测试任务接口
 */
@RestController
@RequestMapping("/testTask")
@Slf4j
public class TestTaskController {
    @Resource
    private TestTaskService testTaskService;

    @Resource
    private UserService userService;

    @Resource
    private TestCaseService testCaseService;


    @PostMapping("/upload")
    public BaseResponse<String> upload(@RequestBody UploadFileRequest request) {
        List<UploadFileVO> files = request.getFiles();
        StringBuilder stringBuilder = new StringBuilder();
        for (UploadFileVO file : files) {
            TestCase testCase = new TestCase();
            testCase.setCode(file.getFileCode());
            testCase.setName(file.getFileName());
            testCase.setRunStatus(file.getFileType());
            testCase.setLanguage("Java");
            testCase.setRemark("file size " + file.getFileSize());
            testCaseService.saveOrUpdate(testCase);
            stringBuilder.append(testCase.getId()).append(",");
        }
        return ResultUtils.success(stringBuilder.substring(0, stringBuilder.length() - 1));
    }

    /**
     *
     *
     * @description: 添加测试任务
     * @param testTaskAddRequest
     * @param
     * @return:
     * @author: linhuaixu
     * @time: 2023/5/17 19:58
     */

    @PostMapping("/add")
    public BaseResponse<Long> addTestTask(@RequestBody TestTaskAddRequest testTaskAddRequest){
        if(testTaskAddRequest==null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        TestTask testTask=new TestTask();
        BeanUtils.copyProperties(testTaskAddRequest,testTask);
        //校验
        testTaskService.validTestTask(testTask,true);
//        User loginUser = userService.getLoginUser(request);
        testTask.setUserId(1L);
        boolean save = testTaskService.save(testTask);
        if(!save){
            throw new BusinessException(ErrorCode.OPERATION_ERROR);
        }
        Long id = testTask.getId();
        return ResultUtils.success(id);
    }

    /**
     *
     *
     * @description: 删除测试任务
     * @param deleteRequest
     * @param
     * @return:
     * @author: linhuaixu
     * @time: 2023/5/17 20:07
     */

    @PostMapping("/delete")
    public BaseResponse<Boolean> deleteTestTask(@RequestBody DeleteRequest deleteRequest){
        if(deleteRequest==null || deleteRequest.getId()<=0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
//        User loginUser = userService.getLoginUser(request);
        Long id = deleteRequest.getId();
        //判断是否存在
        TestTask testTask = testTaskService.getById(id);
        if(testTask==null){
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }
        //仅管理员和本人可以删除
//        if(!testTask.getUserId().equals(loginUser.getId()) && !userService.isAdmin(request)){
//            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
//        }
        boolean b = testTaskService.removeById(id);
        return ResultUtils.success(b);
    }

    /**
     *
     *
     * @description: 测试任务更新
     * @param testTaskUpdateRequest
     * @return:
     * @author: linhuaixu
     * @time: 2023/5/17 20:14
     */

    @PostMapping("/update")
    public BaseResponse<Boolean> updateTestTask(@RequestBody TestTaskUpdateRequest testTaskUpdateRequest){
        if(testTaskUpdateRequest==null || testTaskUpdateRequest.getId()<=0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        TestTask testTask=new TestTask();
        BeanUtils.copyProperties(testTaskUpdateRequest,testTask);
        //参数校验
        testTaskService.validTestTask(testTask,false);
//        User loginUser = userService.getLoginUser(request);
        Long id = testTaskUpdateRequest.getId();
        //判断是否存在
        TestTask oldTestTask = testTaskService.getById(id);
        if(oldTestTask==null){
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }
        testTask.setUserId(1L);
        //仅本人和管理员可以修改
//        if(!oldTestTask.getUserId().equals(loginUser.getId()) && !userService.isAdmin(request)){
//            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
//        }
        boolean b = testTaskService.updateById(testTask);
        return ResultUtils.success(b);
    }

    /**
     *
     *
     * @description: 测试任务静态划分执行
     * @param testTaskUpdateRequest
     * @return:
     * @author: linhuaixu
     * @time: 2023/5/17 20:14
     */

    @PostMapping("/executeStatic")
    public BaseResponse<Boolean> executeStaticTestTask(@RequestBody TestTaskUpdateRequest testTaskUpdateRequest){

        if(testTaskUpdateRequest==null || testTaskUpdateRequest.getId()<=0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        TestTask testTask=new TestTask();
        testTask.setId(testTaskUpdateRequest.getId());
        testTask.setStaticStatus(1);
        testTaskService.updateById(testTask);
        long startTime = System.currentTimeMillis();
        TestTask anotherTestTask = testTaskService.getById(testTaskUpdateRequest.getId());
        String[] split = anotherTestTask.getTestCaseList().split(",");
        List<String> list = Arrays.asList(split);
        //执行静态排序
        try {

            HashMap<String, String> map = new HashMap<>();
            for (String fruit : list) {
                map.put(fruit, testCaseService.getById(fruit).getCode());
            }
            Map<String, Double> averageSimilarityMap = new HashMap<>();
            for (int i = 0; i < list.size(); i++) {
                double sum=0;
                for (int j = 0; j < list.size(); j++) {
                    sum+= getSimilar(map.get(list.get(i)), map.get(list.get(j)));
                }
                averageSimilarityMap.put(list.get(i), sum /(list.size()-1));

            }
            Collections.sort(list, (index1, index2) -> {
                double avgSim1 = averageSimilarityMap.get(index1);
                double avgSim2 = averageSimilarityMap.get(index2);
                return Double.compare(avgSim2, avgSim1); // 降序排序
            });

            Thread.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
//        testTask.setStaticStatus(2);
        BeanUtils.copyProperties(testTaskUpdateRequest,testTask);
        testTask.setStaticStatus(2);
        long endTime = System.currentTimeMillis();
        long duration = endTime - startTime; // 计算运行时间
        testTask.setStaticTime((int) duration);
        //参数校验
        testTaskService.validTestTask(testTask,false);
        Long id = testTaskUpdateRequest.getId();
        //判断是否存在
        TestTask oldTestTask = testTaskService.getById(id);
        if(oldTestTask==null){
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }
//        String[] split = testTask.getTestCaseList().split(",");
//        List<String> list = Arrays.asList(split);
//        Collections.shuffle(list);
        StringBuilder stringBuilder = new StringBuilder();
        for(String s : list){
            stringBuilder.append(s).append(",");
        }
        testTask.setTestCaseList(stringBuilder.substring(0, stringBuilder.length() - 1));
        testTask.setStaticLog("执行完成时间：" + DateUtil.now() + " 执行耗时：" + testTask.getStaticTime() + " 执行状态（0-未开始, 1-执行中, 2-成功, 3-失败）：" + testTask.getStaticStatus());
        boolean b = testTaskService.updateById(testTask);
        return ResultUtils.success(b);
    }

    /**
     *
     *
     * @description: 测试任务动态调整执行
     * @param testTaskUpdateRequest
     * @return:
     * @author: linhuaixu
     * @time: 2023/5/17 20:14
     */

    @PostMapping("/executeDynamic")
    public BaseResponse<ExecuteCodeResponse> executeDynamicTestTask(@RequestBody TestTaskUpdateRequest testTaskUpdateRequest){
        if(testTaskUpdateRequest==null || testTaskUpdateRequest.getId()<=0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        TestTask testTask=new TestTask();
        testTask.setId(testTaskUpdateRequest.getId());
        testTask.setDynamicStatus(1);
        testTaskService.updateById(testTask);
        long startTime = System.currentTimeMillis();
        TestTask anotherTestTask = testTaskService.getById(testTaskUpdateRequest.getId());
        String[] split = anotherTestTask.getTestCaseList().split(",");
        List<String> list = Arrays.asList(split);



        list.sort(Comparator.comparingInt((id) -> {
            TestCase testCase = testCaseService.getById(id);
            return testCase.getRunStatus();
        }));
        long endTime = System.currentTimeMillis();
        long duration = endTime - startTime; // 计算运行时间


        StringBuilder stringBuilder = new StringBuilder();
        for(String s : list){
            stringBuilder.append(s).append(",");
            // 将这些id对应的test case的result time status等修改

        }
        testTask.setDynamicLog( stringBuilder.substring(0, stringBuilder.length() - 1));

        testTaskService.updateById(testTask);


        BeanUtils.copyProperties(testTaskUpdateRequest,testTask);
        testTask.setDynamicStatus(2);
        testTask.setDynamicTime((int) duration);
        //参数校验
        testTaskService.validTestTask(testTask,false);
        Long id = testTaskUpdateRequest.getId();
        //判断是否存在
        TestTask oldTestTask = testTaskService.getById(id);
        if(oldTestTask==null){
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }


//        ExecuteCodeRequest executeCodeRequest = new ExecuteCodeRequest();
//        executeCodeRequest.setInputList(new ArrayList<>());
//        executeCodeRequest.setCode("java code");
//        executeCodeRequest.setLanguage("Java");
        ExecuteCodeResponse executeCodeResponse = new ExecuteCodeResponse();
//        testTask.setDynamicLog(executeCodeResponse.getMessage() + "\n \n===============================================\n 动态排序执行结果：" + stringBuilder.substring(0, stringBuilder.length() - 1) + "\n===============================================\n");
        testTaskService.updateById(testTask);

        return ResultUtils.success(executeCodeResponse);
    }
    //计算不同排序下的apfd值的变化
    @PostMapping("/getStaticApfd")
    public BaseResponse<Double> getStaticApfd(@RequestBody TestTaskUpdateRequest testTaskUpdateRequest){
        if(testTaskUpdateRequest==null || testTaskUpdateRequest.getId()<=0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        TestTask anotherTestTask = testTaskService.getById(testTaskUpdateRequest.getId());
        String[] split = anotherTestTask.getTestCaseList().split(",");
        List<String> list = Arrays.asList(split);
        int i =1;
        int count =0;
        int total = 0;
        for(String s : list){

            TestCase testCase = testCaseService.getById(s);

            if(testCase.getRunStatus() == 0)
            {
                count+=i;
                total++;
            }
            // 将这些id对应的test case的result time status等修改
            i++;
        }

        double apfd=0.0;
        apfd = 1 - (double) count /(total*list.size())+ (double) 1 /(2*list.size());

        return ResultUtils.success(apfd);
    }
    //计算不同排序下的apfd值的变化
    @PostMapping("/getDynamicApfd")
    public BaseResponse<Double> getDynamicApfd(@RequestBody TestTaskUpdateRequest testTaskUpdateRequest){
        if(testTaskUpdateRequest==null || testTaskUpdateRequest.getId()<=0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        TestTask anotherTestTask = testTaskService.getById(testTaskUpdateRequest.getId());
        String[] split = anotherTestTask.getDynamicLog().split(",");
        List<String> list = Arrays.asList(split);
        int i =1;
        int count =0;
        int total = 0;
        for(String s : list){

            TestCase testCase = testCaseService.getById(s);

            if(testCase.getRunStatus() == 0)
            {
                count+=i;
                total++;
            }
            // 将这些id对应的test case的result time status等修改
            i++;
        }

        double apfd=0.0;
        apfd = 1 - (double) count /(total*list.size())+ (double) 1 /(2*list.size());
        return ResultUtils.success(apfd);
    }

    /**zip
     * 调用代码沙箱执行测试用例
     * @param executeCodeRequest
     * @return
     */
    public ExecuteCodeResponse executeCode(ExecuteCodeRequest executeCodeRequest) {
        System.out.println("远程代码沙箱");
        String url = "http://localhost:8090/executeCode";
        String json = JSONUtil.toJsonStr(executeCodeRequest);
        String responseStr = HttpUtil.createPost(url).body(json).execute().body();
        if(StringUtils.isBlank(responseStr)){
            throw new BusinessException(ErrorCode.SYSTEM_ERROR,"调用远程代码沙箱错误");
        }
        return JSONUtil.toBean(responseStr, ExecuteCodeResponse.class);
    }
    /**
     *
     *
     * @description: 根据id获取测试任务信息
     * @param id
     * @return:
     * @author: linhuaixu
     * @time: 2023/5/17 20:18
     */

    @GetMapping("/get")
    public BaseResponse<TestTask> getTestTaskById(Long id){
        if(id<=0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        TestTask testTask = testTaskService.getById(id);
        if(testTask.getIsDelete()==1){
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR,"测试任务已删除");
        }
        return ResultUtils.success(testTask);
    }

    /**
     *
     *
     * @description: 获取测试任务列表，仅管理员可以使用
     * @param testTaskQueryRequest
     * @return:
     * @author: linhuaixu
     * @time: 2023/5/17 20:21
     */

    @GetMapping("/list")
    @AuthCheck(mustRole = "admin")
    public BaseResponse<List<TestTask>> listTestTask(TestTaskQueryRequest testTaskQueryRequest){
        TestTask testTaskQuery=new TestTask();
        if(testTaskQueryRequest!=null){
            BeanUtils.copyProperties(testTaskQueryRequest,testTaskQuery);
        }
        QueryWrapper<TestTask> testTaskQueryWrapper = new QueryWrapper<>(testTaskQuery);
        List<TestTask> testTaskList = testTaskService.list(testTaskQueryWrapper);
        return ResultUtils.success(testTaskList);
    }

    /**
     *
     *
     * @description: 分页获取测试任务列表
     * @param testTaskQueryRequest
     * @return:
     * @author: linhuaixu
     * @time: 2023/5/17 20:33
     */

    @GetMapping("/list/page")
    public BaseResponse<Page<TestTask>> listTestTaskByPage(TestTaskQueryRequest testTaskQueryRequest){
        if(testTaskQueryRequest==null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        if(StringUtils.isEmpty(testTaskQueryRequest.getTaskName())){
            testTaskQueryRequest.setTaskName(null);
        }
        TestTask testTask = new TestTask();
        BeanUtils.copyProperties(testTaskQueryRequest,testTask);
        long current = testTaskQueryRequest.getCurrent();
        long pageSize = testTaskQueryRequest.getPageSize();
        String sortField = testTaskQueryRequest.getSortField();
        String sortOrder = testTaskQueryRequest.getSortOrder();
//        String content = testTask.getContent();
//        //content需要支持模糊搜索
//        testTask.setContent(null);
        //限制爬虫
        if(pageSize>50){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        QueryWrapper<TestTask> testTaskQueryWrapper = testTaskService.getQueryWrapper(testTaskQueryRequest);
//        testTaskQueryWrapper.like(StringUtils.isNotBlank(content),"content",content);
//        testTaskQueryWrapper.orderBy(StringUtils.isNotBlank(sortField),
//                sortOrder.equals(CommonConstant.SORT_ORDER_ASC),sortField);
        Page<TestTask> page = testTaskService.page(new Page<>(current, pageSize), testTaskQueryWrapper);
        return ResultUtils.success(page);
    }

    private Double getSimilar(String args1,String args2) {
        String cleanedArgs1 = removeComments(args1);
        String cleanedArgs2 = removeComments(args2);

        // 数据清洗：去除两端空白、转换为小写、去除特殊字符
        String sanitizedArgs1 = cleanedArgs1.trim().toLowerCase().replaceAll("[^a-zA-Z0-9 ]", "");
        String sanitizedArgs2 = cleanedArgs2.trim().toLowerCase().replaceAll("[^a-zA-Z0-9 ]", "");

        // 分词：这里简单地使用空格进行分词
        String[] words1 = sanitizedArgs1.split("\\s+");
        String[] words2 = sanitizedArgs2.split("\\s+");
        Map<CharSequence, Integer> map = Arrays.stream(args1.split(""))
                .collect(Collectors.toMap(c -> c, c -> 1, Integer::sum));
        Map<CharSequence, Integer> map2 = Arrays.stream(args2.split(""))
                .collect(Collectors.toMap(c -> c, c -> 1, Integer::sum));

        CosineSimilarity cosineSimilarity = new CosineSimilarity();
        Double similar = cosineSimilarity.cosineSimilarity(map, map2);
        return similar;
    }
    private String removeBlockComments(String code) {
        String blockCommentStart = "/*";
        String blockCommentEnd = "*/";
        int indexStart = code.indexOf(blockCommentStart);
        while (indexStart != -1) {
            int indexEnd = code.indexOf(blockCommentEnd, indexStart + blockCommentStart.length());
            if (indexEnd == -1) {
                // 如果没有找到注释结束标记，则移除从注释开始标记到字符串结束的所有内容
                code = code.substring(0, indexStart);
                break;
            } else {
                // 移除找到的多行注释
                code = code.substring(0, indexStart) + code.substring(indexEnd + blockCommentEnd.length());
            }
            indexStart = code.indexOf(blockCommentStart);
        }
        return code;
    }
    private String removeComments(String code) {
        // 去除多行注释
        code = removeBlockComments(code);
        // 去除单行注释
        code = removeLineComments(code);
        return code;
    }
    private String removeLineComments(String code) {
        String lineCommentStart = "//";
        StringBuilder builder = new StringBuilder();
        boolean isInsideBlockComment = false;
        for (int i = 0; i < code.length(); i++) {
            char currentChar = code.charAt(i);
            if (isInsideBlockComment) {
                if (code.startsWith("*/", i)) {
                    // 多行注释结束
                    i += "*/".length() - 1;
                    isInsideBlockComment = false;
                }
                continue;
            } else {
                if (code.startsWith(lineCommentStart, i)) {
                    // 单行注释开始，停止添加字符到builder
                    break;
                } else if (code.startsWith("/*", i)) {
                    // 多行注释开始
                    isInsideBlockComment = true;
                }
                builder.append(currentChar);
            }
        }
        return builder.toString();
    }
}